from flask import Response, request
from flask_login import current_user  # type: ignore
from flask_restful import Resource,reqparse, marshal_with  # type: ignore
from urllib.parse import quote
from core.file import helpers as file_helpers
import services
from configs import app_config
from controllers.errors.error import FilenameNotExistsError

from fields.file_fields_def import file_fields, upload_config_fields
from libs.login import login_required
import services.errors
import services.errors.file
from services.file_service import FileService

from controllers.errors.file_error import (
    FileTooLargeError,
    NoFileUploadedError,
    TooManyFilesError,
    UnsupportedFileTypeError,
)

PREVIEW_WORDS_LIMIT = 3000

class FilePreviewURLApi(Resource):
    @login_required
    def get(self):
        file_id = request.args.get("file_id")
        if file_id:
            data = {
                "code":"success",
                "file_preview_url":file_helpers.get_signed_file_url(upload_file_id=file_id)
            }
            return data,200
        else:
            return {"code":"failed","message":"file_id is requried"},400 
class FileApi(Resource):

    @login_required
    @marshal_with(file_fields)
    def post(self):
        file = request.files["file"]

        if "file" not in request.files:
            raise NoFileUploadedError()

        if len(request.files) > 1:
            raise TooManyFilesError()

        if not file.filename:
            raise FilenameNotExistsError

        try:
            upload_file = FileService.upload_file(
                filename=file.filename,
                content=file.read(),
                mimetype=file.mimetype,
                user=current_user,
            )
            upload_file.preview_url = upload_file.source_url
        except services.errors.file.FileTooLargeError as file_too_large_error:
            raise FileTooLargeError(file_too_large_error.description)
        except services.errors.file.UnsupportedFileTypeError:
            raise UnsupportedFileTypeError()

        return upload_file, 201
    
class FilePreviewApi(Resource):
    def get(self, file_id):
        file_id = str(file_id)

        parser = reqparse.RequestParser()
        parser.add_argument("timestamp", type=str, required=True, location="args")
        parser.add_argument("nonce", type=str, required=True, location="args")
        parser.add_argument("sign", type=str, required=True, location="args")
        parser.add_argument("as_attachment", type=bool, required=False, default=False, location="args")

        args = parser.parse_args()

        if not args["timestamp"] or not args["nonce"] or not args["sign"]:
            return {"content": "Invalid request."}, 400

        try:
            generator, upload_file = FileService.get_file_generator_by_file_id(
                file_id=file_id,
                timestamp=args["timestamp"],
                nonce=args["nonce"],
                sign=args["sign"],
            )
        except services.errors.file.UnsupportedFileTypeError:
            raise UnsupportedFileTypeError()

        response = Response(
            generator,
            mimetype=upload_file.mime_type,
            direct_passthrough=True,
            headers={},
        )
        if upload_file.size > 0:
            response.headers["Content-Length"] = str(upload_file.size)
        if args["as_attachment"]:
            encoded_filename = quote(upload_file.name)
            response.headers["Content-Disposition"] = f"attachment; filename*=UTF-8''{encoded_filename}"
        response.headers["Content-Type"] = "application/octet-stream"

        return response